---
title: Common Patterns
description: Frequently used code patterns.
---

{/* prettier-ignore-start */}
{/* prettier-ignore-end */}

import { Aside, Card, Code, FileTree } from '@astrojs/starlight/components';

Frequently used code patterns.

## `asChild` prop

Most primitive components have an `asChild` prop. When it is set to `true`, it passes all of its props to its immediate child and renders the child instead of the primitive. To make this possible, the internal implementation of the primitive uses the `Slot` primitive.


<Aside type="tip" title='The Slot Primitive'>
  This primitive merges all of its props with its first child's props and renders the child. It is useful for creating components that can be used as a wrapper around other components.
</ Aside>

### Examples

#### Implementation with an `asChild` prop

Using the `asChild` prop to conditionally render a custom `Button` as a `Pressable` or a `Slot.Pressable`.

<Code lang='tsx' title="~/example/button" code={`
import * as Slot from '@rn-primitives/slot'
import { Pressable, PressableProps } from 'react-native'

export function Button({ asChild, onPress: onPressProp, ...props }: PressableProps & { asChild?: boolean }) {
  function onPress(ev) {
    console.log('Button pressed')
    onPressProp?.(ev)
  }

  // If asChild is true, it does not render a Pressable, instead it passes all of its props to the first child (which needs to be of type Pressable).
  const Component = asChild ? Pressable : Slot.Pressable
  return <Component onPress={onPress} {...props} />
}
`} />

#### Use of a componnent that has an `asChild` prop

Setting the `asChild` prop to `true` to pass all of the `Button` props to the `Pressable` component.

<Code lang='tsx' title="~/other/thing" code={`
import { Button } from '~/example/button'
import { Pressable, Text } from 'react-native'

function Thing(){
    return (
        <Button asChild>
            {/* On Press, it will also log "Button pressed" since the \`Button\` props will be merged and passed to the \`Pressable\` */}
            <Pressable onPress={() => {
                console.log('Pressed')
            }}>
                <Text>Press me</Text>
            </Pressable>
        </Button>
    )
}
`} />


## Forwarding Refs

Refs are used for [Direct Manipulation](https://reactnative.dev/docs/direct-manipulation). A common pratice is to set a ref to a component, then use the ref to call methods or access properties of the component.

### Passing a ref to `react-native` components

Passing a `ref` to the `TextInput` component, allows us to call the `focus` method when the `Pressable` is pressed.

<Code lang='tsx' title="~/example/button" code={`
import * as React from 'react'
import { TextInput, View, Pressable, View } from 'react-native'

function Example() {
  const inputRef = React.useRef<TextInput>(null)

  function onPress() {
    inputRef.current?.focus()
  }

  return (
    <View>
      <Pressable onPress={onPress}>
        <Text>Focus</Text>
      </Pressable>
      <TextInput ref={inputRef} />
    </View>
    )
}
`} />

### Custom components with ref

In React, the `ref` prop is a reserved prop since it needs to be handled differently. To forward a ref to a child component, you must use the `React.forwardRef` function.

**Creating a component that accepts a `ref`**

<Code lang='tsx' title="~/example/custom-input" code={`
import * as React from 'react'
import { TextInput, TextInputProps, View, Pressable, View } from 'react-native'

const CustomInput = React.forwardRef<TextInput, TextInputProps>((props, ref) => {
  return <TextInput ref={ref} {...props} />
})

function Example() {
  const inputRef = React.useRef<TextInput>(null)

  function onPress() {
    inputRef.current?.focus()
  }

  return (
    <View>
      <Pressable onPress={onPress}>
        <Text>Focus</Text>
      </Pressable>
      <CustomInput ref={inputRef} />
    </View>
    )
}
`} />

<Aside>
  Most `/ui` and `/primitive` components are wrapped with a `React.forwardRef` function, so you can pass a `ref` to them.
</Aside>

## Programmatically Showing and Hiding Components

For most components, you can use props to manipulate the visibility of it or its children components. For example, you can pass the `open` prop to the [`AlertDialog`](/components/alert-dialog/#alertdialog) to show or hide it.
However, for some components, the position of its content depends on the `onPress` or `onLongPress` events. In this case, you will need to pass a `ref` to the trigger component and call a method to show or hide it.

#### Example with content that depends on the trigger position

```tsx
import * as HoverCardPrimitive from '@rn-primitives/hover-card';
import { Text, View } from 'react-native';
import * as React from 'react';

function OnMountExample() {
  const triggerRef = React.useRef<React.ElementRef<typeof HoverCardPrimitive.Trigger>>(null);

   React.useEffect(() => {
    const timeout = setTimeout(() => {
      triggerRef.current?.open();
      // Wait for items to be properly layed out and wait for the animation to finish
    }, 100 + 200);

    return () => {
      clearTimeout(timeout);
    };
  }, []);

  return (
        <HoverCardPrimitive.Root>
          <HoverCardPrimitive.Trigger ref={triggerRef}>
              <Text>@nextjs</Text>
          </HoverCardPrimitive.Trigger>
          <HoverCardPrimitive.Content>
            <View>
              <Text>@nextjs</Text>
              <Text>
                The React Framework – created and maintained by @vercel.
              </Text>
              <View>
                <Text>
                  Joined December 2021
                </Text>
              </View>
            </View>
          </HoverCardPrimitive.Content>
        </HoverCardPrimitive.Root>
  );
}
```

## A Portal Component inside a Presentation Modal screen

1. Use the `useModalPortalRoot` hook in the screen with the presentation of `modal`. 
2. Adjust the bottom content insets to make sure the content is not hidden by the bottom safe area.
3. Wrap the screen content with a View and pass the rootProps to it.
4. Place the `PortalHost` inside the View with the rootProps as its last child.
5. Pass the sideOffset from the `useModalPortalRoot` hook to the `SelectContent` component.
6. Pass the `portalHost` name to the `SelectContent` component to render the content inside the `PortalHost` with the same name

```tsx
import { PortalHost, useModalPortalRoot } from '@rn-primitives/portal';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectLabel,
  SelectTrigger,
  SelectValue,
} from '~/components/ui/select';

/**
 * This screen is a Stack.Screen with a presentation of `modal`.
*/
export default function ModalScreen() {
  const insets = useSafeAreaInsets();
  const { sideOffset, ...rootProps } = useModalPortalRoot();
  const contentInsets = {
    top: insets.top,
    // Make sure the content is not hidden by the bottom safe area
    bottom: insets.bottom + Math.abs(sideOffset),
    left: 16,
    right: 16,
  };

// Wrap the screen content with a View and pass the rootProps to it
  return (
     <View {...rootProps}>
        <View className='flex-1 justify-center items-center'>
        <Select defaultValue={{ value: 'apple', label: 'Apple' }}>
            <SelectTrigger>
              <SelectValue
                className='text-foreground text-sm native:text-lg'
                placeholder='Select a fruit'
              />
            </SelectTrigger>
            <SelectContent
              insets={contentInsets}
              // Pass the sideOffset from the useModalPortalRoot hook
              sideOffset={sideOffset}
              className='w-full'
              // Pass the portalHost name from below to the SelectContent
              portalHost='modal-example'
            >
              <SelectGroup>
                <SelectLabel>Fruits</SelectLabel>
                <SelectItem label='Apple' value='apple'>
                  Apple
                </SelectItem>
                <SelectItem label='Banana' value='banana'>
                  Banana
                </SelectItem>
                <SelectItem label='Blueberry' value='blueberry'>
                  Blueberry
                </SelectItem>
                <SelectItem label='Grapes' value='grapes'>
                  Grapes
                </SelectItem>
                <SelectItem label='Pineapple' value='pineapple'>
                  Pineapple
                </SelectItem>
              </SelectGroup>
            </SelectContent>
          </Select>
        </View>
        {/* Place the Postal Host inside the View with the rootProps */}
        <PortalHost name='modal-example' />
     </View>
  )
}
```

<Aside type="caution" title="For the web">
 It has been reported that the web might require additional adjustments. Please check out the [Github Issue](https://github.com/mrzachnugent/react-native-reusables/issues/136#issuecomment-2133941424) for the solution
</Aside>